{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2025 Google LLC."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "cellView": "form",
        "id": "tuOe1ymfHZPu"
      },
      "outputs": [],
      "source": [
        "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yeadDkMiISin"
      },
      "source": [
        "# Gemini API: Function calling with Python"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lEXQ3OwKIa-O"
      },
      "source": [
        "<a target=\"_blank\" href=\"https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Function_calling.ipynb\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" height=30/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "df1767a3d1cc"
      },
      "source": [
        " Function calling lets developers create a description of a function in their code, then pass that description to a language model in a request. The response from the model includes the name of a function that matches the description and the arguments to call it with. Function calling lets you use functions as tools in generative AI applications, and you can define more than one function within a single request.\n",
        "\n",
        "This notebook provides code examples to help you get started. The documentation's [quickstart](https://ai.google.dev/gemini-api/docs/function-calling#python) is also a good place to start understanding function calling."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hY2NtS3jV56U"
      },
      "source": [
        "## Setup"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d5027929de8f"
      },
      "source": [
        "### Install dependencies"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 22,
      "metadata": {
        "id": "9OEoeosRTv-5"
      },
      "outputs": [],
      "source": [
        "%pip install -qU 'google-genai>=1.0.0'"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "x-hHZfLZ7FfH"
      },
      "source": [
        "### Set up your API key\n",
        "\n",
        "To run the following cell, your API key must be stored it in a Colab Secret named `GOOGLE_API_KEY`. If you don't already have an API key, or you're not sure how to create a Colab Secret, see the [Authentication ![image](https://storage.googleapis.com/generativeai-downloads/images/colab_icon16.png)](../quickstarts/Authentication.ipynb) quickstart for an example."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 23,
      "metadata": {
        "id": "ab9ASynfcIZn"
      },
      "outputs": [],
      "source": [
        "from google import genai\n",
        "from google.colab import userdata\n",
        "\n",
        "GOOGLE_API_KEY = userdata.get(\"GOOGLE_API_KEY\")\n",
        "client = genai.Client(api_key=GOOGLE_API_KEY)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zpaKynP8qLw1"
      },
      "source": [
        "### Choose a model\n",
        "\n",
        "Function calling works on all Gemini models."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 24,
      "metadata": {
        "id": "sEK4ZDVGqJ5H"
      },
      "outputs": [],
      "source": [
        "MODEL_ID = \"gemini-2.5-flash\" # @param [\"gemini-2.5-flash-lite\", \"gemini-2.5-flash\", \"gemini-2.5-pro\",\"gemini-3-pro-preview\"] {\"allow-input\":true, isTemplate: true}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3f383614ec30"
      },
      "source": [
        "## Setting up Functions as Tools"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b82c1aecb657"
      },
      "source": [
        "To use function calling, pass a list of functions to the `tools` parameter when creating a [`GenerativeModel`](https://ai.google.dev/api/python/google/generativeai/GenerativeModel). The model uses the function name, docstring, parameters, and parameter type annotations to decide if it needs the function to best answer a prompt.\n",
        "\n",
        "> Important: The SDK converts function parameter type annotations to a format the API understands (`genai.types.FunctionDeclaration`). The API only supports a limited selection of parameter types, and the Python SDK's automatic conversion only supports a subset of that: `AllowedTypes = int | float | bool | str | list['AllowedTypes'] | dict`\n",
        "\n",
        "\n",
        "**Example: Lighting System Functions**\n",
        "\n",
        "Here are 3 functions controlling a hypothetical lighting system. Note the docstrings and type hints."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "metadata": {
        "id": "C8J_H1hSp4m-"
      },
      "outputs": [],
      "source": [
        "def enable_lights():\n",
        "    \"\"\"Turn on the lighting system.\"\"\"\n",
        "    print(\"LIGHTBOT: Lights enabled.\")\n",
        "\n",
        "\n",
        "def set_light_color(rgb_hex: str):\n",
        "    \"\"\"Set the light color. Lights must be enabled for this to work.\"\"\"\n",
        "    print(f\"LIGHTBOT: Lights set to {rgb_hex}.\")\n",
        "\n",
        "def stop_lights():\n",
        "    \"\"\"Stop flashing lights.\"\"\"\n",
        "    print(\"LIGHTBOT: Lights turned off.\")\n",
        "\n",
        "light_controls = [enable_lights, set_light_color, stop_lights]\n",
        "instruction = \"\"\"\n",
        "  You are a helpful lighting system bot. You can turn\n",
        "  lights on and off, and you can set the color. Do not perform any\n",
        "  other tasks.\n",
        "\"\"\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ry0JsK405KwS"
      },
      "source": [
        "## Basic Function Calling with Chat"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9l4wdq8b5Nuy"
      },
      "source": [
        "Function calls naturally fit into multi-turn conversations. The Python SDK's `ChatSession (client.chats.create(...))` is ideal for this, as it automatically handles conversation history.\n",
        "\n",
        "Furthermore, `ChatSession` simplifies function calling execution via its `automatic_function_calling` feature (enabled by default), which will be explored more later. For now, let's see a basic interaction where the model decides to call a function."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "id": "-yuQ2gCY5ujD"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "LIGHTBOT: Lights enabled.\n",
            "No problem, I can turn the lights on for you.\n",
            "\n"
          ]
        }
      ],
      "source": [
        "chat = client.chats.create(\n",
        "    model=MODEL_ID,\n",
        "    config={\n",
        "        \"tools\": light_controls,\n",
        "        \"system_instruction\": instruction,\n",
        "        # automatic_function_calling defaults to enabled\n",
        "    }\n",
        ")\n",
        "\n",
        "response = chat.send_message(\"It's awful dark in here...\")\n",
        "\n",
        "print(response.text)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "q1UsMG3FqYrC"
      },
      "source": [
        "## Examining Function Calls and Execution History\n",
        "\n",
        "To understand what happened in the background, you can examine the chat history.\n",
        "\n",
        "The `Chat.history` property stores a chronological record of the conversation between the user and the Gemini model. You can get the history using `Chat.get_history()`. Each turn in the conversation is represented by a `genai.types.Content` object, which contains the following information:\n",
        "\n",
        "**Role**: Identifies whether the content originated from the \"user\" or the \"model\".\n",
        "\n",
        "**Parts**: A list of genai.types.Part objects that represent individual components of the message. With a text-only model, these parts can be:\n",
        "\n",
        "* **Text**: Plain text messages.\n",
        "* **Function Call (genai.types.FunctionCall)**: A request from the model to execute a specific function with provided arguments.\n",
        "* **Function Response (genai.types.FunctionResponse)**: The result returned by the user after executing the requested function.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "metadata": {
        "id": "SBNAqSexqZlZ"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "It's awful dark in here..."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={} name='enable_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='enable_lights' response={'result': None} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "No problem, I can turn the lights on for you.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "from IPython.display import Markdown, display\n",
        "\n",
        "def print_history(chat):\n",
        "  for content in chat.get_history():\n",
        "      display(Markdown(\"###\" + content.role + \":\"))\n",
        "      for part in content.parts:\n",
        "          if part.text:\n",
        "              display(Markdown(part.text))\n",
        "          if part.function_call:\n",
        "              print(\"Function call: {\", part.function_call, \"}\")\n",
        "          if part.function_response:\n",
        "              print(\"Function response: {\", part.function_response, \"}\")\n",
        "      print(\"-\" * 80)\n",
        "\n",
        "print_history(chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CS84-2yG7A--"
      },
      "source": [
        "This history shows the flow:\n",
        "\n",
        "1. **User**: Sends the message.\n",
        "\n",
        "2. **Model**: Responds not with text, but with a `FunctionCall` requesting `enable_lights`.\n",
        "\n",
        "3. **User (SDK)**: The `ChatSession` automatically executes `enable_lights()` because `automatic_function_calling` is enabled. It sends the result back as a `FunctionResponse`.\n",
        "\n",
        "4. **Model**: Uses the function's result (\"Lights enabled.\") to formulate the final text response."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CsCZArT47p5T"
      },
      "source": [
        "## Automatic Function Execution (Python SDK Feature)\n",
        "\n",
        "As demonstrated above, the `ChatSession` in the Python SDK has a powerful feature called Automatic Function Execution. When enabled (which it is by default), if the model responds with a FunctionCall, the SDK will:\n",
        "\n",
        "1. Find the corresponding Python function in the provided `tools`.\n",
        "\n",
        "2. Execute the function with the arguments provided by the model.\n",
        "\n",
        "3. Send the function's return value back to the model in a `FunctionResponse`.\n",
        "\n",
        "4. Return only the model's final response (usually text) to your code.\n",
        "\n",
        "This significantly simplifies the workflow for common use cases.\n",
        "\n",
        "**Example: Math Operations**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 28,
      "metadata": {
        "id": "r1FnK3EB8jgQ"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "That would be 2508 mittens in total.\n"
          ]
        }
      ],
      "source": [
        "from google.genai import types # Ensure types is imported\n",
        "\n",
        "def add(a: float, b: float):\n",
        "    \"\"\"returns a + b.\"\"\"\n",
        "    return a + b\n",
        "\n",
        "def subtract(a: float, b: float):\n",
        "    \"\"\"returns a - b.\"\"\"\n",
        "    return a - b\n",
        "\n",
        "def multiply(a: float, b: float):\n",
        "    \"\"\"returns a * b.\"\"\"\n",
        "    return a * b\n",
        "\n",
        "def divide(a: float, b: float):\n",
        "    \"\"\"returns a / b.\"\"\"\n",
        "    if b == 0:\n",
        "        return \"Cannot divide by zero.\"\n",
        "    return a / b\n",
        "\n",
        "operation_tools = [add, subtract, multiply, divide]\n",
        "\n",
        "chat = client.chats.create(\n",
        "    model=MODEL_ID,\n",
        "    config={\n",
        "        \"tools\": operation_tools,\n",
        "        \"automatic_function_calling\": {\"disable\": False} # Enabled by default\n",
        "    }\n",
        ")\n",
        "\n",
        "response = chat.send_message(\n",
        "    \"I have 57 cats, each owns 44 mittens, how many mittens is that in total?\"\n",
        ")\n",
        "\n",
        "print(response.text)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "metadata": {
        "id": "cU2TO5-S8tmp"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "I have 57 cats, each owns 44 mittens, how many mittens is that in total?"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'a': 57, 'b': 44} name='multiply' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='multiply' response={'result': 2508} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "That would be 2508 mittens in total."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "print_history(chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a8A6qJ668ywT"
      },
      "source": [
        "Automatic execution handled the `multiply` call seamlessly."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1BzsV6MxLnZD"
      },
      "source": [
        "## Automatic Function Schema Declaration\n",
        "\n",
        "A key convenience of the Python SDK is its ability to automatically generate the required `FunctionDeclaration` schema from your Python functions. It inspects:\n",
        "\n",
        "- **Function Name**: (`func.__name__`)\n",
        "\n",
        "- **Docstring**: Used for the function's description.\n",
        "\n",
        "- **Parameters**: Names and type annotations (`int`, `str`, `float`, `bool`, `list`, `dict`). Docstrings for parameters (if using specific formats like Google style) can also enhance the description.\n",
        "\n",
        "- **Return Type Annotation**: Although not strictly used by the model for deciding which function to call, it's good practice.\n",
        "\n",
        "You generally don't need to create `FunctionDeclaration` objects manually when using Python functions directly as tools.\n",
        "\n",
        "However, you can generate the schema explicitly using `genai.types.FunctionDeclaration.from_callable` if you need to inspect it, modify it, or use it in scenarios where you don't have the Python function object readily available."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "metadata": {
        "id": "qrYRieAuL2hs"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "    \"description\": \"Set the light color. Lights must be enabled for this to work.\",\n",
            "    \"name\": \"set_light_color\",\n",
            "    \"parameters\": {\n",
            "        \"properties\": {\n",
            "            \"rgb_hex\": {\n",
            "                \"type\": \"STRING\"\n",
            "            }\n",
            "        },\n",
            "        \"required\": [\n",
            "            \"rgb_hex\"\n",
            "        ],\n",
            "        \"type\": \"OBJECT\"\n",
            "    }\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "import json\n",
        "\n",
        "set_color_declaration = types.FunctionDeclaration.from_callable(\n",
        "    callable = set_light_color,\n",
        "    client = client\n",
        ")\n",
        "\n",
        "print(json.dumps(set_color_declaration.to_json_dict(), indent=4))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eea8e3a0b89f"
      },
      "source": [
        "## Manual function calling"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9610f3465a69"
      },
      "source": [
        "For more control, or if automatic function calling is not available,  you can process [`genai.types.FunctionCall`](https://googleapis.github.io/python-genai/genai.html#genai.types.FunctionCall) requests from the model yourself. This would be the case if:\n",
        "\n",
        "- You use a `Chat` with the default `\"automatic_function_calling\": {\"disable\": True}`.\n",
        "- You use [`Client.model.generate_content`](https://googleapis.github.io/python-genai/genai.html#genai.types.) (and manage the chat history yourself)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "34ffab0bf365"
      },
      "source": [
        "**Example: Movies**\n",
        "\n",
        "The following example is a rough equivalent of the [function calling single-turn curl sample](https://ai.google.dev/docs/function_calling#function-calling-single-turn-curl-sample) in Python. It uses functions that return (mock) movie playtime information, possibly from a hypothetical API:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 31,
      "metadata": {
        "id": "46ba0fa3d09a"
      },
      "outputs": [],
      "source": [
        "def find_movies(description: str, location: str):\n",
        "    \"\"\"find movie titles currently playing in theaters based on any description, genre, title words, etc.\n",
        "\n",
        "    Args:\n",
        "        description: Any kind of description including category or genre, title words, attributes, etc.\n",
        "        location: The city and state, e.g. San Francisco, CA or a zip code e.g. 95616\n",
        "    \"\"\"\n",
        "    return [\"Barbie\", \"Oppenheimer\"]\n",
        "\n",
        "\n",
        "def find_theaters(location: str, movie: str):\n",
        "    \"\"\"Find theaters based on location and optionally movie title which are currently playing in theaters.\n",
        "\n",
        "    Args:\n",
        "        location: The city and state, e.g. San Francisco, CA or a zip code e.g. 95616\n",
        "        movie: Any movie title\n",
        "    \"\"\"\n",
        "    return [\"Googleplex 16\", \"Android Theatre\"]\n",
        "\n",
        "\n",
        "def get_showtimes(location: str, movie: str, theater: str, date: str):\n",
        "    \"\"\"\n",
        "    Find the start times for movies playing in a specific theater.\n",
        "\n",
        "    Args:\n",
        "      location: The city and state, e.g. San Francisco, CA or a zip code e.g. 95616\n",
        "      movie: Any movie title\n",
        "      thearer: Name of the theater\n",
        "      date: Date for requested showtime\n",
        "    \"\"\"\n",
        "    return [\"10:00\", \"11:00\"]\n",
        "\n",
        "theater_functions = [find_movies, find_theaters, get_showtimes]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "11631c6e2b10"
      },
      "source": [
        "After using `generate_content()` to ask a question, the model requests a `function_call`:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 32,
      "metadata": {
        "id": "5e3b9c84d883"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{\n",
            "    \"function_call\": {\n",
            "        \"args\": {\n",
            "            \"location\": \"Mountain View, CA\",\n",
            "            \"movie\": \"Barbie\"\n",
            "        },\n",
            "        \"name\": \"find_theaters\"\n",
            "    }\n",
            "}\n"
          ]
        }
      ],
      "source": [
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=\"Which theaters in Mountain View, CA show the Barbie movie?\",\n",
        "    config = {\n",
        "        \"tools\": theater_functions,\n",
        "        \"automatic_function_calling\": {\"disable\": True}\n",
        "    }\n",
        ")\n",
        "\n",
        "print(json.dumps(response.candidates[0].content.parts[0].to_json_dict(), indent=4))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kuldoypuAC1i"
      },
      "source": [
        "Since this is not using a `ChatSession` with automatic function calling, you have to call the function yourself.\n",
        "\n",
        "A very simple way to do this would be with `if` statements:\n",
        "\n",
        "```python\n",
        "if function_call.name == 'find_theaters':\n",
        "  find_theaters(**function_call.args)\n",
        "elif ...\n",
        "```\n",
        "\n",
        "However, since you already made the `theater_functions` list, this can be simplified to:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 33,
      "metadata": {
        "id": "rjkZ8MA00Coc"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "['Googleplex 16', 'Android Theatre']\n"
          ]
        }
      ],
      "source": [
        "def call_function(function_call, functions):\n",
        "    function_name = function_call.name\n",
        "    function_args = function_call.args\n",
        "    # Find the function object from the list based on the function name\n",
        "    for func in functions:\n",
        "        if func.__name__ == function_name:\n",
        "            return func(**function_args)\n",
        "\n",
        "part = response.candidates[0].content.parts[0]\n",
        "\n",
        "# Check if it's a function call; in real use you'd need to also handle text\n",
        "# responses as you won't know what the model will respond with.\n",
        "if part.function_call:\n",
        "    result = call_function(part.function_call, theater_functions)\n",
        "\n",
        "print(result)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XLWrHOatBtRz"
      },
      "source": [
        "Finally, pass the response plus the message history to the next `generate_content()` call to get a final text response from the model. The next code cell is showing on purpose different ways to write down `Content` so you can choose the one that you prefer."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 34,
      "metadata": {
        "id": "xr13VGnJAgZv"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The Barbie movie is currently playing at the Googleplex 16 and Android Theatre in Mountain View.\n"
          ]
        }
      ],
      "source": [
        "from google.genai import types\n",
        "# Build the message history\n",
        "messages = [\n",
        "    types.Content(\n",
        "        role=\"user\",\n",
        "        parts=[\n",
        "            types.Part(\n",
        "                text=\"Which theaters in Mountain View show the Barbie movie?.\"\n",
        "            )\n",
        "        ]\n",
        "    ),\n",
        "    types.Content(\n",
        "        role=\"model\",\n",
        "        parts=[part]\n",
        "    ),\n",
        "    types.Content(\n",
        "        role=\"tool\",\n",
        "        parts=[\n",
        "            types.Part.from_function_response(\n",
        "                name=part.function_call.name,\n",
        "                response={\"output\":result},\n",
        "            )\n",
        "        ]\n",
        "    )\n",
        "]\n",
        "\n",
        "# Generate the next response\n",
        "response = client.models.generate_content(\n",
        "    model=MODEL_ID,\n",
        "    contents=messages,\n",
        "    config = {\n",
        "        \"tools\": theater_functions,\n",
        "        \"automatic_function_calling\": {\"disable\": True}\n",
        "    }\n",
        ")\n",
        "print(response.text)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8ZFiMVth9Kjb"
      },
      "source": [
        "This demonstrates the manual workflow: call, check, execute, respond, call again."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EuwKoNIhGBJN"
      },
      "source": [
        "## Parallel function calls\n",
        "\n",
        "The Gemini API can call multiple functions in a single turn. This caters for scenarios where there are multiple function calls that can take place independently to complete a task.\n",
        "\n",
        "First set the tools up. Unlike the movie example above, these functions do not require input from each other to be called so they should be good candidates for parallel calling."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 35,
      "metadata": {
        "id": "cJ-mSixWGqLv"
      },
      "outputs": [],
      "source": [
        "def power_disco_ball(power: bool) -> bool:\n",
        "    \"\"\"Powers the spinning disco ball.\"\"\"\n",
        "    print(f\"Disco ball is {'spinning!' if power else 'stopped.'}\")\n",
        "    return True\n",
        "\n",
        "def start_music(energetic: bool, loud: bool, bpm: int) -> str:\n",
        "    \"\"\"Play some music matching the specified parameters.\n",
        "\n",
        "    Args:\n",
        "      energetic: Whether the music is energetic or not.\n",
        "      loud: Whether the music is loud or not.\n",
        "      bpm: The beats per minute of the music.\n",
        "\n",
        "    Returns: The name of the song being played.\n",
        "    \"\"\"\n",
        "    print(f\"Starting music! {energetic=} {loud=}, {bpm=}\")\n",
        "    return \"Never gonna give you up.\"\n",
        "\n",
        "\n",
        "def dim_lights(brightness: float) -> bool:\n",
        "    \"\"\"Dim the lights.\n",
        "\n",
        "    Args:\n",
        "      brightness: The brightness of the lights, 0.0 is off, 1.0 is full.\n",
        "    \"\"\"\n",
        "    print(f\"Lights are now set to {brightness:.0%}\")\n",
        "    return True\n",
        "\n",
        "house_fns = [power_disco_ball, start_music, dim_lights]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zlrmXN7fxQi0"
      },
      "source": [
        "Now call the model with an instruction that could use all of the specified tools."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 36,
      "metadata": {
        "id": "21ecYHLgIsCl"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n",
            "Disco ball is spinning!\n",
            "Starting music! energetic=True loud=True, bpm=130\n",
            "Lights are now set to 30%\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "Turn this place into a party!"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'energetic': True, 'bpm': 130, 'loud': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'energetic': True, 'bpm': 130, 'loud': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'energetic': True, 'loud': True, 'bpm': 130} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'loud': True, 'energetic': True, 'bpm': 130} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'loud': True, 'energetic': True, 'bpm': 130} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'energetic': True, 'loud': True, 'bpm': 130} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'energetic': True, 'bpm': 130, 'loud': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'loud': True, 'bpm': 130, 'energetic': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'bpm': 130, 'loud': True, 'energetic': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'bpm': 130, 'loud': True, 'energetic': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='power_disco_ball' response={'result': True} }\n",
            "Function response: { id=None name='start_music' response={'result': 'Never gonna give you up.'} }\n",
            "Function response: { id=None name='dim_lights' response={'result': True} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'power': True} name='power_disco_ball' }\n",
            "Function call: { id=None args={'bpm': 130, 'loud': True, 'energetic': True} name='start_music' }\n",
            "Function call: { id=None args={'brightness': 0.3} name='dim_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "# You generally set \"mode\": \"any\" to make sure Gemini actually *uses* the given tools.\n",
        "party_chat = client.chats.create(\n",
        "    model=MODEL_ID,\n",
        "    config={\n",
        "        \"tools\": house_fns,\n",
        "        \"tool_config\" : {\n",
        "            \"function_calling_config\": {\n",
        "                \"mode\": \"any\"\n",
        "            }\n",
        "        }\n",
        "    }\n",
        ")\n",
        "\n",
        "# Call the API\n",
        "response = party_chat.send_message(\n",
        "    \"Turn this place into a party!\"\n",
        ")\n",
        "\n",
        "\n",
        "print_history(party_chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "t6iYpty7yZct"
      },
      "source": [
        "Notice the single model turn contains three FunctionCall parts, which the SDK then executed before getting the final text response."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TxXGT3n4AQhk"
      },
      "source": [
        "## Compositional Function Calling\n",
        "The model can chain function calls across multiple turns, using the result from one call to inform the next. This allows for complex, multi-step reasoning and task completion.\n",
        "\n",
        "**Example: Finding Specific Movie Showtimes**\n",
        "\n",
        "Let's reuse the theater_functions and ask a more complex query that requires finding movies first, then potentially theaters, then showtimes."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 37,
      "metadata": {
        "id": "1jGiexKsAolU"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OK. I have found comedy movies playing in Mountain View, CA on 01/01/2025, the theaters they are playing in, and their showtimes. The comedy movies playing on 01/01/2025 in Mountain View, CA are Barbie and Oppenheimer.\n",
            "\n",
            "Barbie is playing at Googleplex 16 and Android Theatre at 10:00 and 11:00.\n",
            "Oppenheimer is playing at Googleplex 16 and Android Theatre at 10:00 and 11:00.\n",
            "\n",
            "--- History ---\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "\n",
              "  Find comedy movies playing in Mountain View, CA on 01/01/2025.\n",
              "  First, find the movie titles.\n",
              "  Then, find the theaters showing those movies.\n",
              "  Finally, find the showtimes for each movie at each theater.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'location': 'Mountain View, CA', 'description': 'comedy'} name='find_movies' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='find_movies' response={'result': ['Barbie', 'Oppenheimer']} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'location': 'Mountain View, CA', 'movie': 'Barbie'} name='find_theaters' }\n",
            "Function call: { id=None args={'movie': 'Oppenheimer', 'location': 'Mountain View, CA'} name='find_theaters' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='find_theaters' response={'result': ['Googleplex 16', 'Android Theatre']} }\n",
            "Function response: { id=None name='find_theaters' response={'result': ['Googleplex 16', 'Android Theatre']} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={'date': '01/01/2025', 'location': 'Mountain View, CA', 'movie': 'Barbie', 'theater': 'Googleplex 16'} name='get_showtimes' }\n",
            "Function call: { id=None args={'theater': 'Android Theatre', 'date': '01/01/2025', 'location': 'Mountain View, CA', 'movie': 'Barbie'} name='get_showtimes' }\n",
            "Function call: { id=None args={'theater': 'Googleplex 16', 'movie': 'Oppenheimer', 'date': '01/01/2025', 'location': 'Mountain View, CA'} name='get_showtimes' }\n",
            "Function call: { id=None args={'theater': 'Android Theatre', 'location': 'Mountain View, CA', 'movie': 'Oppenheimer', 'date': '01/01/2025'} name='get_showtimes' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='get_showtimes' response={'result': ['10:00', '11:00']} }\n",
            "Function response: { id=None name='get_showtimes' response={'result': ['10:00', '11:00']} }\n",
            "Function response: { id=None name='get_showtimes' response={'result': ['10:00', '11:00']} }\n",
            "Function response: { id=None name='get_showtimes' response={'result': ['10:00', '11:00']} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "OK. I have found comedy movies playing in Mountain View, CA on 01/01/2025, the theaters they are playing in, and their showtimes. The comedy movies playing on 01/01/2025 in Mountain View, CA are Barbie and Oppenheimer.\n",
              "\n",
              "Barbie is playing at Googleplex 16 and Android Theatre at 10:00 and 11:00.\n",
              "Oppenheimer is playing at Googleplex 16 and Android Theatre at 10:00 and 11:00."
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "chat = client.chats.create(\n",
        "    model = MODEL_ID,\n",
        "    config = {\n",
        "        \"tools\": theater_functions,\n",
        "    }\n",
        ")\n",
        "\n",
        "response = chat.send_message(\"\"\"\n",
        "  Find comedy movies playing in Mountain View, CA on 01/01/2025.\n",
        "  First, find the movie titles.\n",
        "  Then, find the theaters showing those movies.\n",
        "  Finally, find the showtimes for each movie at each theater.\n",
        "\"\"\"\n",
        ")\n",
        "\n",
        "print(response.text)\n",
        "print(\"\\n--- History ---\")\n",
        "print_history(chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "s7J-nyTN8hL-"
      },
      "source": [
        "Here you can see that the model made seven calls to answer your question and used the outputs of them in the subsequent calls and in the final answer."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BsS8_hhNBpLS"
      },
      "source": [
        "## Function Calling Configuration using Modes\n",
        "\n",
        "While AUTO mode (or the SDK's default automatic execution) is often sufficient, you can precisely control when and which functions the model is allowed to call using the tool_config parameter during model/chat initialization or in send_message.\n",
        "\n",
        "The `tool_config` accepts a ToolConfig object, which contains a `FunctionCallingConfig`.\n",
        "\n",
        "The `FunctionCallingConfig` has two main fields:\n",
        "\n",
        "- `mode`: Controls the overall function calling behavior (AUTO, ANY, NONE).\n",
        "\n",
        "- `allowed_function_names`: An optional list of function names the model is restricted to calling in this turn."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UGZtasE4CObk"
      },
      "source": [
        "### AUTO (Default Mode)\n",
        "\n",
        "- Behavior: The model decides whether to respond with text or to call one or more functions from the provided `tools`. This is the most flexible mode.\n",
        "\n",
        "- SDK Default: When using ChatSession with automatic execution enabled, the underlying behavior effectively uses `AUTO` mode unless overridden by `tool_config`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "metadata": {
        "id": "mggqLU55CZlj"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "LIGHTBOT: Lights enabled.\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "Turn on the lights!"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={} name='enable_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='enable_lights' response={'result': None} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "OK. I have turned on the lights.\n"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "chat = client.chats.create(model=MODEL_ID)\n",
        "\n",
        "response = chat.send_message(\n",
        "    message=\"Turn on the lights!\",\n",
        "    config={\n",
        "        \"system_instruction\": instruction,\n",
        "        \"tools\": light_controls,\n",
        "        \"tool_config\" : types.ToolConfig(\n",
        "            function_calling_config=types.FunctionCallingConfig(\n",
        "                mode=\"auto\"\n",
        "            )\n",
        "        )\n",
        "    }\n",
        ")\n",
        "\n",
        "print_history(chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3s9_3yVfDfTZ"
      },
      "source": [
        "### NONE Mode\n",
        "Behavior: The model is explicitly prohibited from calling any functions, even if tools are provided. It will only respond with text. Useful for turns where you want a purely conversational response."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 39,
      "metadata": {
        "id": "Yw5Vn3y3DkG6"
      },
      "outputs": [
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "Hello light-bot, what can you do?"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "Hello! I can help you with your lights. I can:\n",
              "*   Turn lights on\n",
              "*   Turn lights off\n",
              "*   Set the color of the lights"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "none_chat = client.chats.create(model=MODEL_ID)\n",
        "\n",
        "response = none_chat.send_message(\n",
        "    message=\"Hello light-bot, what can you do?\",\n",
        "    config={\n",
        "        \"system_instruction\": instruction,\n",
        "        \"tools\": light_controls, # Tools are provided\n",
        "        \"tool_config\" : types.ToolConfig(\n",
        "            function_calling_config=types.FunctionCallingConfig(\n",
        "                mode=\"none\"\n",
        "            )\n",
        "        ) # but NONE mode prevents their use\n",
        "    }\n",
        ")\n",
        "\n",
        "print_history(none_chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2nUTj3qoDxU_"
      },
      "source": [
        "### ANY Mode\n",
        "- Behavior: Forces the model to call at least one function.\n",
        "\n",
        "  - If allowed_function_names is set, the model must choose one or more functions from that list.\n",
        "\n",
        "  - If allowed_function_names is not set, the model must choose one or more functions from the full tools list.\n",
        "\n",
        "- If automatic function calling is enabled, the SDK will call functions automatically until [maximum_remote_calls](https://googleapis.github.io/python-genai/genai.html#genai.types.AutomaticFunctionCallingConfig.maximum_remote_calls) is reached (default: 10).\n",
        "- To allow x automatic function calls, set maximum_remote_calls to x + 1. [Read more](https://pypi.org/project/google-genai/#:~:text=Function%20calling%20with%20ANY%20tools%20config%20mode)\n",
        "- Use Case: Useful when the application state dictates that the next step must involve a specific action or set of actions."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 40,
      "metadata": {
        "id": "7fmljA2RDw9a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "LIGHTBOT: Lights enabled.\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/markdown": [
              "Make this place PURPLE!"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={} name='enable_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###user:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function response: { id=None name='enable_lights' response={'result': None} }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        },
        {
          "data": {
            "text/markdown": [
              "###model:"
            ],
            "text/plain": [
              "<IPython.core.display.Markdown object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Function call: { id=None args={} name='enable_lights' }\n",
            "--------------------------------------------------------------------------------\n"
          ]
        }
      ],
      "source": [
        "chat = client.chats.create(model=MODEL_ID)\n",
        "\n",
        "response = chat.send_message(\n",
        "    \"Make this place PURPLE!\",\n",
        "    config={\n",
        "        \"system_instruction\": instruction,\n",
        "        \"tools\": light_controls, # Provide all tools\n",
        "        \"tool_config\" : {\n",
        "            \"function_calling_config\": {\n",
        "                \"mode\": \"any\"\n",
        "            }\n",
        "        },\n",
        "        \"automatic_function_calling\": {\n",
        "            \"maximum_remote_calls\" : 1\n",
        "        }\n",
        "      } # But restrict to available_fns with ANY mode\n",
        ")\n",
        "\n",
        "print_history(chat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7c2f31504490"
      },
      "source": [
        "## Next Steps\n",
        "### Useful API references:\n",
        "\n",
        "- The [genai.Client](https://googleapis.github.io/python-genai/genai.html#module-genai.client) class\n",
        "  - Its [Client.models.generate_content](https://googleapis.github.io/python-genai/genai.html#genai.models.Models.generate_content) method has a [genai.types.GenerateContentConfig](https://googleapis.github.io/python-genai/genai.html#genai.types.GenerateContentConfig) field that is in particular used to set the tools and function calls.\n",
        "    - The config's `tools` attribute contains a list of [genai.types.Tools](https://googleapis.github.io/python-genai/genai.html#genai.types.Tool) objects.\n",
        "    - The `function_declarations` attribute contains a list of [genai.types.FunctionDeclarations](https://googleapis.github.io/python-genai/genai.html#genai.types.FunctionDeclaration) objects.\n",
        "- The [response](https://googleapis.github.io/python-genai/genai.html#genai.types.GenerateContentResponse)'s [candidate](https://googleapis.github.io/python-genai/genai.html#genai.types.Candidate)'s [content](https://googleapis.github.io/python-genai/genai.html#genai.types.Content)'s [parts](https://googleapis.github.io/python-genai/genai.html#genai.types.Part) may contain a [genai.types.FunctionCall](https://googleapis.github.io/python-genai/genai.html#genai.types.FunctionCall), in `response.candidates[0].contents.parts[0]`.\n",
        "- if `automatic_function_calling` is not disabled, the [genai.Chats](https://googleapis.github.io/python-genai/genai.html#module-genai.chats) session executes the call, and sends back the [genai.types.FunctionResponse]https://googleapis.github.io/python-genai/genai.html#genai.types.FunctionResponse).\n",
        "- In response to a [FunctionCall](https://googleapis.github.io/python-genai/genai.html#genai.types.FunctionCall) the model always expects a [FunctionResponse](https://googleapis.github.io/python-genai/genai.html#genai.types.FunctionResponse).\n",
        "- If you reply manually using [Chats.send_message](https://googleapis.github.io/python-genai/genai.html#genai.chats.AsyncChat.send_message) or [models.generate_content](https://googleapis.github.io/python-genai/genai.html#genai.models.Models.generate_content) remember thart the API is stateless you have to send the whole conversation history (a list of [Content](https://googleapis.github.io/python-genai/genai.html#genai.types.Content) objects), not just the last one containing the `FunctionResponse`.\n",
        "\n",
        "### Related examples\n",
        "\n",
        "Check out these examples using function calling to give you more ideas on how to use that very useful feature:\n",
        "* [Barista Bot](../examples/Agents_Function_Calling_Barista_Bot.ipynb), an agent to order coffee\n",
        "* [Browser-as-a-tool](../examples/Browser_as_a_tool.ipynb), using function calling to call a web-browser.\n",
        "* Using function calling to [re-rank seach results](../examples/Search_reranking_using_embeddings.ipynb).\n",
        "* [Using tools with the Live API](../quickstarts/Get_started_LiveAPI_tools.ipynb), using function calling and other tools with the Live APIs.\n",
        "\n",
        "### Continue your discovery of the Gemini API\n",
        "\n",
        "Learn how to control how the Gemini API interact with your functions in the [function calling config](../quickstarts/Function_calling_config.ipynb) quickstart, discover how to control the model output in [JSON](../quickstarts/JSON_mode.ipynb) or using an [Enum](../quickstarts/Enum.ipynb) or learn how the Gemini API can generate and run code by itself using [Code execution](../quickstarts/Code_Execution.ipynb)"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "hY2NtS3jV56U"
      ],
      "name": "Function_calling.ipynb",
      "toc_visible": true
    },
    "google": {
      "image_path": "/site-assets/images/share.png",
      "keywords": [
        "examples",
        "googleai",
        "samplecode",
        "python",
        "embed",
        "function"
      ]
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
